#include <iostream>
#include <unistd.h>
#include <string>
#include "Thread.hpp"
#include "LockGuard.hpp"

int ticket = 10000; // 一共1万张票（全局共享资源）
// pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;  // 定义锁

std::string GetThreadName()
{
    static int number = 1; // 生命周期随进程，且只在当前作用域有效
    char name[64];
    snprintf(name, sizeof(name), "Thread-%d", number++);
    return name;
}

// 加锁：
//  1. 我们要尽可能的给少的代码加锁
//  2. 一般加锁，都是给临界区加锁
void GetTicket(pthread_mutex_t *mutex)
{
    while (true)
    {
        {
            LockGuard Lockguard(mutex);
            // pthread_mutex_lock(mutex);    // 申请锁本身是安全的，原子的
            if (ticket > 0) // 一个线程在临界区中访问临界资源的时候，可能发生切换
            {
                usleep(1000); // 充当抢票时间
                printf("get a ticket: %d\n", ticket);
                ticket--;
                // pthread_mutex_unlock(mutex);
            }
            else
            {
                // ticket == 0了就不抢了
                // pthread_mutex_unlock(mutex);
                break;
            }
        }
        // 实际情况，还有后续的动作
    }
}

int main()
{
    pthread_mutex_t mutex;
    pthread_mutex_init(&mutex, nullptr);

    std::string name1 = GetThreadName();
    Thread<pthread_mutex_t *> t1(GetTicket, name1, &mutex);

    std::string name2 = GetThreadName();
    Thread<pthread_mutex_t *> t2(GetTicket, name2, &mutex);

    std::string name3 = GetThreadName();
    Thread<pthread_mutex_t *> t3(GetTicket, name3, &mutex);

    std::string name4 = GetThreadName();
    Thread<pthread_mutex_t *> t4(GetTicket, name4, &mutex);

    t1.Start();
    t2.Start();
    t3.Start();
    t4.Start();

    t1.Join();
    t2.Join();
    t3.Join();
    t4.Join();

    pthread_mutex_destroy(&mutex);
    return 0;
}
